import asyncio

# object is awaitable if it can be used in an await expression
# There are three main types of awaitable object: coroutines, Tasks, and Futures


async def nested():
    await asyncio.sleep(1)
    return 42


async def nested1(a: int):
    return 24 + a


async def main():
    # Nothing happens if we just call "nested()".
    # A coroutine object is created but not awaited,
    # so it *won't run at all*.

    # Let's do it differently now and await it:
    future1 = await nested()  # will print "42".
    future2 = await nested1(future1)
    print(future2)


async def main1():
    await nested()

    # this is also valid
    await asyncio.gather(
        nested(),
        nested1()
    )


if __name__ == "__main__":
    asyncio.run(main())
